/* Copyright Statement:
 *
 * ECARX Technology Limited is the owner of the copyright and the trade secret of this software.
 * Without permission, no one has the right to obtain, disclose or use this software in any way.
 *
 */
#define LOG_TAG "STR_OS_DHUVehicleHal"

#include <android/log.h>
#include <log/log.h>

#include <dirent.h>
#include <fcntl.h>
#include <sstream>
#include <unistd.h>
#include "ECarXInputProvider.h"

namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {

namespace impl {

ECarXInputProvider::kevent::kevent() {
    bzero(this, sizeof(*this));
}

bool ECarXInputProvider::kevent::isKeypress() const {
    return type == EV_KEY;
}

bool ECarXInputProvider::kevent::isKeydown() const {
    return isKeypress() && (value == 1);
}

bool ECarXInputProvider::kevent::isKeyup() const {
    return isKeypress() && (value == 0);
}

ECarXInputProvider::ECarXInputProvider(){
    mInputFd = openInput(KEY_INPUT_NAME);
    ALOGD("STR_OS_ECarXInputProvider mInputFd get %d\n",mInputFd);
}

ECarXInputProvider::~ECarXInputProvider(){
    if (mReadThread->joinable()) {
        mReadThread->join();
    }
    if (mInputFd > 0){
        ::close(mInputFd);
        mInputFd = -1;
    }
}

void ECarXInputProvider::registerKeyCodeCallback(KeyCodeCallback&& callback){
     if (mCallback) {
        ALOGW("STR_OS_ECarXInputProvider Cannot register multiple callbacks!");
        return;
    }
    mCallback = std::move(callback);
}

int ECarXInputProvider::openInput(const char* inputName){
    int fd = -1;
    const char *dirname = "/dev/input";
    char devname[PATH_MAX];
    char *filename;
    DIR *dir;
    struct dirent *de;
    dir = opendir(dirname);
    if (dir == NULL) {
        return -1;
    }
    strcpy(devname, dirname);
    filename = devname + strlen(devname);
    *filename++ = '/';
    while((de = readdir(dir))) {
        if(de->d_name[0] == '.' &&
           (de->d_name[1] == '\0' ||
            (de->d_name[1] == '.' && de->d_name[2] == '\0')))
            continue;
        strcpy(filename, de->d_name);

        fd = open(devname, O_RDWR);
        if (fd>=0) {
            char name[80];
            if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
                name[0] = '\0';
            }
            if (!strcmp(name, inputName)) {
                ALOGD("STR_OS_ECarXInputProvider  keyinput get fd %s\n",devname);
                break;
            } else {
                close(fd);
                fd = -1;
            }
        }
    }
    closedir(dir);
    return fd;
}

void ECarXInputProvider::startLoop(){
    mReadThread = std::make_unique<std::thread>(std::bind(&ECarXInputProvider::readEventThread, this));
}

void ECarXInputProvider::stop(){
    if (mReadThread->joinable()) {
        mReadThread->join();
    }
    if (mInputFd > 0){
        ::close(mInputFd);
        mInputFd = -1;
    }

}

void ECarXInputProvider::onKeyDown(int keyCode){
    ALOGD("STR_OS_ECarXInputProvider %s", __func__);
    return mCallback(keyCode);
}

void ECarXInputProvider::readEventThread(){
    while (true){
        if (mInputFd < 0)
        {
            ALOGW("STR_OS_ECarXInputProvider mInputFd open failed");
            return;
        }
        kevent evt;
        auto cnt = ::read(mInputFd, &evt, sizeof(evt));

        if (cnt < static_cast<decltype(cnt)>(sizeof(evt))) {
            ALOGW("STR_OS_ECarXInputProvider key event error");
            continue;
        }
        if (!evt.isKeypress()) {
             continue;
        }
        ALOGD("STR_OS_ECarXInputProvider keycode %u (down = %s)", evt.code, evt.isKeydown() ? "true" : "false");
        if (evt.isKeydown()){
            onKeyDown(evt.code);
        }
    }
}

}  // namespace impl

}  // namespace V2_0
}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
}  // namespace android
